home *** CD-ROM | disk | FTP | other *** search
/ Team Palmtops 7 / Palmtops_numero07.iso / WinCE / SDKWindowsCE / HandHeldPCPro30 / sdk.exe / Jupiter SDK / data1.cab / MFC / src / ctlpbag.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1999-02-19  |  13.7 KB  |  623 lines

  1. // This is a part of the Microsoft Foundation Classes C++ library.
  2. // Copyright (C) 1992-1998 Microsoft Corporation
  3. // All rights reserved.
  4. //
  5. // This source code is only intended as a supplement to the
  6. // Microsoft Foundation Classes Reference and related
  7. // electronic documentation provided with the library.
  8. // See these sources for detailed information regarding the
  9. // Microsoft Foundation Classes product.
  10.  
  11. #include "stdafx.h"
  12.  
  13. #ifdef AFXCTL_PROP_SEG
  14. #pragma code_seg(AFXCTL_PROP_SEG)
  15. #endif
  16.  
  17. #ifdef _DEBUG
  18. #undef THIS_FILE
  19. static char THIS_FILE[] = __FILE__;
  20. #endif
  21.  
  22. #define new DEBUG_NEW
  23.  
  24. /////////////////////////////////////////////////////////////////////////////
  25. // CBlobProperty
  26.  
  27. class CBlobProperty : public IPersistStream
  28. {
  29. public:
  30.     CBlobProperty(HGLOBAL pBlob = NULL);
  31.     HGLOBAL GetBlob();
  32.  
  33.     STDMETHOD_(ULONG, AddRef)();
  34.     STDMETHOD_(ULONG, Release)();
  35.     STDMETHOD(QueryInterface)(REFIID, LPVOID*);
  36.  
  37.     STDMETHOD(GetClassID)(LPCLSID);
  38.     STDMETHOD(IsDirty)();
  39.     STDMETHOD(Load)(LPSTREAM);
  40.     STDMETHOD(Save)(LPSTREAM, BOOL);
  41.     STDMETHOD(GetSizeMax)(ULARGE_INTEGER*);
  42.  
  43. protected:
  44.     long m_dwRef;
  45.     HGLOBAL m_hBlob;
  46. };
  47.  
  48. CBlobProperty::CBlobProperty(HGLOBAL hBlob) :
  49.     m_hBlob(hBlob),
  50.     m_dwRef(1)
  51. {
  52. }
  53.  
  54. HGLOBAL CBlobProperty::GetBlob()
  55. {
  56.     return m_hBlob;
  57. }
  58.  
  59. STDMETHODIMP_(ULONG) CBlobProperty::AddRef()
  60. {
  61.     return InterlockedIncrement(&m_dwRef);
  62. }
  63.  
  64. STDMETHODIMP_(ULONG) CBlobProperty::Release()
  65. {
  66.     if (InterlockedDecrement(&m_dwRef) > 0)
  67.         return m_dwRef;
  68.  
  69.     delete this;
  70.     return 0;
  71. }
  72.  
  73. STDMETHODIMP CBlobProperty::QueryInterface(REFIID riid, LPVOID* ppvObj)
  74. {
  75.     if (IsEqualIID(riid, IID_IUnknown) ||
  76.         IsEqualIID(riid, IID_IPersist) ||
  77.         IsEqualIID(riid, IID_IPersistStream))
  78.     {
  79.         AddRef();
  80.         *ppvObj = this;
  81.         return S_OK;
  82.     }
  83.  
  84.     *ppvObj = NULL;
  85.     return E_NOINTERFACE;
  86. }
  87.  
  88. AFX_STATIC_DATA const CLSID _afx_CLSID_BlobProperty =
  89. { 0xf6f07540, 0x42ec, 0x11ce, { 0x81, 0x35, 0x0, 0xaa, 0x0, 0x4b, 0xb8, 0x51 } };
  90.  
  91. STDMETHODIMP CBlobProperty::GetClassID(LPCLSID pClsid)
  92. {
  93.     *pClsid = _afx_CLSID_BlobProperty;
  94.     return S_OK;
  95. }
  96.  
  97. STDMETHODIMP CBlobProperty::IsDirty()
  98. {
  99.     return S_OK;
  100. }
  101.  
  102. STDMETHODIMP CBlobProperty::Load(LPSTREAM pStream)
  103. {
  104.     ULONG cb;
  105.     ULONG cbRead;
  106.     HRESULT hr = pStream->Read(&cb, sizeof(ULONG), &cbRead);
  107.  
  108.     if (FAILED(hr))
  109.         return hr;
  110.  
  111.     if (sizeof(ULONG) != cbRead)
  112.         return E_FAIL;
  113.  
  114.     HGLOBAL hBlobNew = WCE_FCTN(GlobalAlloc)(GMEM_MOVEABLE, sizeof(ULONG)+cb);
  115.     if (hBlobNew == NULL)
  116.         return E_OUTOFMEMORY;
  117.  
  118.     void* pBlobNew = WCE_FCTN(GlobalLock)(hBlobNew);
  119.     *(ULONG*)pBlobNew = cb;
  120.     hr = pStream->Read(((ULONG*)pBlobNew)+1, cb, &cbRead);
  121.     WCE_FCTN(GlobalUnlock)(hBlobNew);
  122.  
  123.     if (FAILED(hr))
  124.     {
  125.         WCE_FCTN(GlobalFree)(hBlobNew);
  126.         return hr;
  127.     }
  128.     if (cb != cbRead)
  129.     {
  130.         WCE_FCTN(GlobalFree)(hBlobNew);
  131.         return E_FAIL;
  132.     }
  133.  
  134.     WCE_FCTN(GlobalFree)(m_hBlob);
  135.     m_hBlob = hBlobNew;
  136.     return S_OK;
  137. }
  138.  
  139. STDMETHODIMP CBlobProperty::Save(LPSTREAM pStream, BOOL)
  140. {
  141.     void* pBlob = WCE_FCTN(GlobalLock)(m_hBlob);
  142.     if (pBlob == NULL)
  143.         return E_OUTOFMEMORY;
  144.  
  145.     ULONG cb = sizeof(ULONG) + *(ULONG*)pBlob;
  146.     ULONG cbWritten;
  147.     HRESULT hr = pStream->Write(pBlob, cb, &cbWritten);
  148.  
  149.     WCE_FCTN(GlobalUnlock)(m_hBlob);
  150.  
  151.     if (FAILED(hr))
  152.         return hr;
  153.  
  154.     if (cb != cbWritten)
  155.         return E_FAIL;
  156.  
  157.     return S_OK;
  158. }
  159.  
  160. STDMETHODIMP CBlobProperty::GetSizeMax(ULARGE_INTEGER* pcbSize)
  161. {
  162.     void* pBlob = WCE_FCTN(GlobalLock)(m_hBlob);
  163.     if (pBlob == NULL)
  164.         return E_OUTOFMEMORY;
  165.  
  166.     pcbSize->HighPart = 0;
  167.     pcbSize->LowPart = sizeof(ULONG) + *(ULONG*)pBlob;
  168.  
  169.     WCE_FCTN(GlobalUnlock)(m_hBlob);
  170.     return S_OK;
  171. }
  172.  
  173. /////////////////////////////////////////////////////////////////////////////
  174. // CPropbagPropExchange
  175.  
  176. class CPropbagPropExchange : public CPropExchange
  177. {
  178. public:
  179.     CPropbagPropExchange(LPPROPERTYBAG pPropBag, LPERRORLOG pErrorLog,
  180.         BOOL bLoading, BOOL bSaveAllProperties=FALSE);
  181.     ~CPropbagPropExchange();
  182.  
  183. // Operations
  184.     virtual BOOL ExchangeProp(LPCTSTR pszPropName, VARTYPE vtProp,
  185.                 void* pvProp, const void* pvDefault = NULL);
  186.     virtual BOOL ExchangeBlobProp(LPCTSTR pszPropName, HGLOBAL* phBlob,
  187.                 HGLOBAL hBlobDefault = NULL);
  188.     virtual BOOL ExchangeFontProp(LPCTSTR pszPropName, CFontHolder& font,
  189.                 const FONTDESC* pFontDesc, LPFONTDISP pFontDispAmbient);
  190.     virtual BOOL ExchangePersistentProp(LPCTSTR pszPropName,
  191.                 LPUNKNOWN* ppUnk, REFIID iid, LPUNKNOWN pUnkDefault);
  192.  
  193. // Implementation
  194.     LPPROPERTYBAG m_pPropBag;
  195.     LPERRORLOG m_pErrorLog;
  196.     BOOL m_bSaveAllProperties;
  197. };
  198.  
  199. CPropbagPropExchange::CPropbagPropExchange(LPPROPERTYBAG pPropBag,
  200.     LPERRORLOG pErrorLog, BOOL bLoading, BOOL bSaveAllProperties) :
  201.     m_pPropBag(pPropBag),
  202.     m_pErrorLog(pErrorLog),
  203.     m_bSaveAllProperties(bSaveAllProperties)
  204. {
  205.     m_bLoading = bLoading;
  206.     if (pPropBag != NULL)
  207.         pPropBag->AddRef();
  208.     if (pErrorLog != NULL)
  209.         pErrorLog->AddRef();
  210. }
  211.  
  212. CPropbagPropExchange::~CPropbagPropExchange()
  213. {
  214.     RELEASE(m_pPropBag);
  215.     RELEASE(m_pErrorLog);
  216. }
  217.  
  218. BOOL CPropbagPropExchange::ExchangeProp(LPCTSTR pszPropName, VARTYPE vtProp,
  219.     void* pvProp, const void* pvDefault)
  220. {
  221.     USES_CONVERSION;
  222.  
  223.     ASSERT_POINTER(m_pPropBag, IPropertyBag);
  224.     ASSERT(AfxIsValidString(pszPropName));
  225.     ASSERT(AfxIsValidAddress(pvProp, 1, FALSE));
  226.     ASSERT((pvDefault == NULL) || AfxIsValidAddress(pvDefault, 1, FALSE));
  227.  
  228.     if (m_pPropBag == NULL)
  229.         return FALSE;
  230.  
  231.     BOOL bSuccess = TRUE;
  232.     VARIANT var;
  233.     AfxVariantInit(&var);
  234.     V_VT(&var) = vtProp;
  235.  
  236.     if (vtProp == VT_LPSTR)
  237.         V_VT(&var) = VT_BSTR;
  238.  
  239.     if (m_bLoading)
  240.     {
  241.         if (FAILED(m_pPropBag->Read(T2COLE(pszPropName), &var, m_pErrorLog)))
  242.             return _AfxCopyPropValue(vtProp, pvProp, pvDefault);
  243.  
  244.         switch (vtProp)
  245.         {
  246.         case VT_UI1:
  247.             *(BYTE*)pvProp = V_UI1(&var);
  248.             break;
  249.  
  250.         case VT_I2:
  251.             *(short*)pvProp = V_I2(&var);
  252.             break;
  253.  
  254.         case VT_I4:
  255.             *(long*)pvProp = V_I4(&var);
  256.             break;
  257.  
  258.         case VT_BOOL:
  259.             *(BOOL*)pvProp = (BOOL)V_BOOL(&var);
  260.             break;
  261.  
  262.         case VT_LPSTR:
  263.         case VT_BSTR:
  264.             *(CString*)pvProp = OLE2CT(V_BSTR(&var));
  265.             break;
  266.  
  267.         case VT_CY:
  268.             *(CY*)pvProp = V_CY(&var);
  269.             break;
  270.  
  271.         case VT_R4:
  272.             memcpy(pvProp, &V_R4(&var), sizeof(float));
  273.             break;
  274.  
  275.         case VT_R8:
  276.             memcpy(pvProp, &V_R8(&var), sizeof(double));
  277.             break;
  278.  
  279.         default:
  280.             bSuccess = FALSE;
  281.         }
  282.     }
  283.     else
  284.     {
  285.         if (m_bSaveAllProperties ||
  286.             !_AfxIsSamePropValue(vtProp, pvProp, pvDefault))
  287.         {
  288.             switch (vtProp)
  289.             {
  290.             case VT_UI1:
  291.                 V_UI1(&var) = *(BYTE*)pvProp;
  292.                 break;
  293.  
  294.             case VT_I2:
  295.                 V_I2(&var) = *(short*)pvProp;
  296.                 break;
  297.  
  298.             case VT_I4:
  299.                 V_I4(&var) = *(long*)pvProp;
  300.                 break;
  301.  
  302.             case VT_BOOL:
  303.                 V_BOOL(&var) = (VARIANT_BOOL)*(BOOL*)pvProp;
  304.                 break;
  305.  
  306.             case VT_LPSTR:
  307.             case VT_BSTR:
  308.                 V_BSTR(&var) = SysAllocString(T2COLE(*(CString*)pvProp));
  309.                 break;
  310.  
  311.             case VT_CY:
  312.                 V_CY(&var) = *(CY*)pvProp;
  313.                 break;
  314.  
  315.             case VT_R4:
  316.                 memcpy(&V_R4(&var), pvProp, sizeof(float));
  317.                 break;
  318.  
  319.             case VT_R8:
  320.                 memcpy(&V_R8(&var), pvProp, sizeof(double));
  321.                 break;
  322.  
  323.             default:
  324.                 return FALSE;
  325.             }
  326.             bSuccess = SUCCEEDED(m_pPropBag->Write(T2COLE(pszPropName), &var));
  327.         }
  328.     }
  329.  
  330.     VariantClear(&var);
  331.     return bSuccess;
  332. }
  333.  
  334. BOOL CPropbagPropExchange::ExchangeBlobProp(LPCTSTR pszPropName,
  335.     HGLOBAL* phBlob, HGLOBAL hBlobDefault)
  336. {
  337.     USES_CONVERSION;
  338.  
  339.     ASSERT_POINTER(m_pPropBag, IPropertyBag);
  340.     ASSERT(AfxIsValidString(pszPropName));
  341.     ASSERT_POINTER(phBlob, HGLOBAL);
  342.  
  343.     BOOL bSuccess = FALSE;
  344.     VARIANT var;
  345.     AfxVariantInit(&var);
  346.     V_VT(&var) = VT_UNKNOWN;
  347.  
  348.     if (m_bLoading)
  349.     {
  350.         if (*phBlob != NULL)
  351.         {
  352.             WCE_FCTN(GlobalFree)(*phBlob);
  353.             *phBlob = NULL;
  354.         }
  355.  
  356.         CBlobProperty* pBlobProp = new CBlobProperty;
  357.         V_UNKNOWN(&var) = pBlobProp;
  358.  
  359.         if (SUCCEEDED(m_pPropBag->Read(T2COLE(pszPropName), &var, m_pErrorLog)))
  360.         {
  361.             *phBlob = pBlobProp->GetBlob();
  362.             bSuccess = TRUE;
  363.         }
  364.         else
  365.         {
  366.             if (hBlobDefault != NULL)
  367.                 bSuccess = _AfxCopyBlob(phBlob, hBlobDefault);
  368.         }
  369.  
  370.         pBlobProp->Release();
  371.     }
  372.     else
  373.     {
  374.         CBlobProperty* pBlobProp = new CBlobProperty(*phBlob);
  375.         V_UNKNOWN(&var) = pBlobProp;
  376.         bSuccess = SUCCEEDED(m_pPropBag->Write(T2COLE(pszPropName), &var));
  377.         pBlobProp->Release();
  378.     }
  379.     return bSuccess;
  380. }
  381.  
  382. BOOL CPropbagPropExchange::ExchangeFontProp(LPCTSTR pszPropName,
  383.     CFontHolder& font, const FONTDESC* pFontDesc,
  384.     LPFONTDISP pFontDispAmbient)
  385. {
  386.     USES_CONVERSION;
  387.  
  388.     ASSERT_POINTER(m_pPropBag, IPropertyBag);
  389.     ASSERT(AfxIsValidString(pszPropName));
  390.     ASSERT_POINTER(&font, CFontHolder);
  391.     ASSERT_NULL_OR_POINTER(pFontDesc, FONTDESC);
  392.     ASSERT_NULL_OR_POINTER(pFontDispAmbient, IFontDisp);
  393.  
  394.     BOOL bSuccess = FALSE;
  395.     VARIANT var;
  396.     AfxVariantInit(&var);
  397.     V_VT(&var) = VT_UNKNOWN;
  398.  
  399.     if (m_bLoading)
  400.     {
  401.         LPFONT pFont = NULL;
  402.  
  403. #if defined(_WIN32_WCE)
  404.             IPersistPropertyBag* ppb;
  405.             bSuccess = 
  406.                 SUCCEEDED(WCE_FCTN(OleCreateFontIndirect)(NULL, IID_IFont, (LPVOID *)&pFont)) &&
  407.                 SUCCEEDED(pFont->QueryInterface(IID_IPersistPropertyBag, (void**)&ppb)) &&
  408.                 SUCCEEDED(ppb->Load(m_pPropBag, m_pErrorLog));
  409. #else // _WIN32_WCE
  410.         bSuccess =
  411.             SUCCEEDED(m_pPropBag->Read(T2COLE(pszPropName), &var,
  412.                 m_pErrorLog)) &&
  413.             SUCCEEDED(V_UNKNOWN(&var)->QueryInterface(IID_IFont,
  414.                 (LPVOID*)&pFont));
  415. #endif // _WIN32_WCE
  416.  
  417.         if (bSuccess)
  418.         {
  419.             ASSERT_POINTER(pFont, IFont);
  420.             font.SetFont(pFont);
  421.         }
  422.         else
  423.         {
  424.             // Initialize font to its default state
  425.             font.InitializeFont(pFontDesc, pFontDispAmbient);
  426.         }
  427.         VariantClear(&var);
  428.     }
  429.     else
  430.     {
  431.         if ((font.m_pFont == NULL) ||
  432.             (_AfxIsSameFont(font, pFontDesc, pFontDispAmbient) &&
  433.                 !m_bSaveAllProperties))
  434.         {
  435.             bSuccess = TRUE;
  436.         }
  437.         else
  438.         {
  439. #if defined(_WIN32_WCE)
  440.             IPersistPropertyBag* ppb;
  441.             font.FontToCeFont(); 
  442.             bSuccess = SUCCEEDED(font.m_pFont->QueryInterface(IID_IPersistPropertyBag, (void**)&ppb)) &&
  443.                        SUCCEEDED(ppb->Save(m_pPropBag, FALSE, TRUE));
  444.             font.RestoreFont();
  445. #else // _WIN32_WCE
  446.             V_UNKNOWN(&var) = font.m_pFont;
  447.             bSuccess = SUCCEEDED(m_pPropBag->Write(T2COLE(pszPropName), &var));
  448. #endif // _WIN32_WCE
  449.         }
  450.     }
  451.  
  452.     return bSuccess;
  453. }
  454.  
  455. BOOL CPropbagPropExchange::ExchangePersistentProp(LPCTSTR pszPropName,
  456.     LPUNKNOWN* ppUnk, REFIID iid, LPUNKNOWN pUnkDefault)
  457. {
  458.     USES_CONVERSION;
  459.  
  460.     ASSERT_POINTER(m_pPropBag, IPropertyBag);
  461.     ASSERT(AfxIsValidString(pszPropName));
  462.     ASSERT_POINTER(ppUnk, LPUNKNOWN);
  463.     ASSERT_NULL_OR_POINTER(pUnkDefault, IUnknown);
  464.  
  465.     BOOL bSuccess = FALSE;
  466.     VARIANT var;
  467.     AfxVariantInit(&var);
  468.     V_VT(&var) = VT_UNKNOWN;
  469.  
  470.     if (m_bLoading)
  471.     {
  472.         RELEASE(*ppUnk);
  473.         *ppUnk = NULL;
  474.  
  475.         bSuccess =
  476.             SUCCEEDED(m_pPropBag->Read(T2COLE(pszPropName), &var,
  477.                 m_pErrorLog)) &&
  478.             SUCCEEDED(V_UNKNOWN(&var)->QueryInterface(iid, (LPVOID*)ppUnk));
  479.  
  480.         if (!bSuccess)
  481.         {
  482.             // Use default value.
  483.             if (pUnkDefault != NULL)
  484.             {
  485.                 bSuccess = SUCCEEDED(pUnkDefault->QueryInterface(iid,
  486.                     (LPVOID*)ppUnk));
  487.             }
  488.             else
  489.             {
  490.                 bSuccess = TRUE;
  491.             }
  492.         }
  493.         VariantClear(&var);
  494.     }
  495.     else
  496.     {
  497.         if ((*ppUnk == NULL) ||
  498.             (_AfxIsSameUnknownObject(iid, *ppUnk, pUnkDefault) &&
  499.                 !m_bSaveAllProperties))
  500.         {
  501.             bSuccess = TRUE;
  502.         }
  503.         else
  504.         {
  505.             V_UNKNOWN(&var) = *ppUnk;
  506.             bSuccess = SUCCEEDED(m_pPropBag->Write(T2COLE(pszPropName), &var));
  507.         }
  508.     }
  509.  
  510.     return bSuccess;
  511. }
  512.  
  513. /////////////////////////////////////////////////////////////////////////////
  514. // COleControl::XPersistPropertyBag
  515.  
  516. STDMETHODIMP_(ULONG) COleControl::XPersistPropertyBag::AddRef()
  517. {
  518.     METHOD_PROLOGUE_EX_(COleControl, PersistPropertyBag)
  519.     return (ULONG)pThis->ExternalAddRef();
  520. }
  521.  
  522. STDMETHODIMP_(ULONG) COleControl::XPersistPropertyBag::Release()
  523. {
  524.     METHOD_PROLOGUE_EX_(COleControl, PersistPropertyBag)
  525.     return (ULONG)pThis->ExternalRelease();
  526. }
  527.  
  528. STDMETHODIMP COleControl::XPersistPropertyBag::QueryInterface(
  529.     REFIID iid, LPVOID* ppvObj)
  530. {
  531.     METHOD_PROLOGUE_EX_(COleControl, PersistPropertyBag)
  532.     return (HRESULT)pThis->ExternalQueryInterface(&iid, ppvObj);
  533. }
  534.  
  535. STDMETHODIMP COleControl::XPersistPropertyBag::GetClassID(LPCLSID lpClassID)
  536. {
  537.     METHOD_PROLOGUE_EX_(COleControl, PersistPropertyBag)
  538.     return pThis->GetClassID(lpClassID);
  539. }
  540.  
  541. STDMETHODIMP COleControl::XPersistPropertyBag::InitNew()
  542. {
  543.     METHOD_PROLOGUE_EX(COleControl, PersistPropertyBag)
  544.  
  545.     // Delegate to OnResetState.
  546.     pThis->OnResetState();
  547.  
  548.     // Unless IOleObject::SetClientSite is called after this, we can
  549.     // count on ambient properties being available while loading.
  550.     pThis->m_bCountOnAmbients = TRUE;
  551.  
  552.     // Properties have been initialized
  553.     pThis->m_bInitialized = TRUE;
  554.  
  555.     // Uncache cached ambient properties
  556.     _afxAmbientCache->Cache(NULL);
  557.  
  558.     return S_OK;
  559. }
  560.  
  561. STDMETHODIMP COleControl::XPersistPropertyBag::Load(LPPROPERTYBAG pPropBag,
  562.     LPERRORLOG pErrorLog)
  563. {
  564.     METHOD_PROLOGUE_EX(COleControl, PersistPropertyBag)
  565.  
  566.     HRESULT hr;
  567.  
  568.     TRY
  569.     {
  570.         CPropbagPropExchange px(pPropBag, pErrorLog, TRUE);
  571.         pThis->DoPropExchange(&px);
  572.         hr = S_OK;
  573.     }
  574.     CATCH_ALL(e)
  575.     {
  576.         hr = E_FAIL;
  577.         DELETE_EXCEPTION(e);
  578.     }
  579.     END_CATCH_ALL
  580.  
  581.     // Properties have probably changed
  582.     pThis->BoundPropertyChanged(DISPID_UNKNOWN);
  583.     pThis->InvalidateControl();
  584.  
  585.     // Clear the modified flag.
  586.     pThis->m_bModified = FALSE;
  587.  
  588.     // Properties have been initialized
  589.     pThis->m_bInitialized = TRUE;
  590.  
  591.     // Uncache cached ambient properties
  592.     _afxAmbientCache->Cache(NULL);
  593.  
  594.     return hr;
  595. }
  596.  
  597. STDMETHODIMP COleControl::XPersistPropertyBag::Save(LPPROPERTYBAG pPropBag,
  598.     BOOL fClearDirty, BOOL fSaveAllProperties)
  599. {
  600.     METHOD_PROLOGUE_EX(COleControl, PersistPropertyBag)
  601.  
  602.     HRESULT hr;
  603.  
  604.     TRY
  605.     {
  606.         CPropbagPropExchange px(pPropBag, NULL, FALSE, fSaveAllProperties);
  607.         pThis->DoPropExchange(&px);
  608.         hr = S_OK;
  609.     }
  610.     CATCH_ALL(e)
  611.     {
  612.         hr = E_FAIL;
  613.         DELETE_EXCEPTION(e);
  614.     }
  615.     END_CATCH_ALL
  616.  
  617.     // Bookkeeping:  Clear the dirty flag, if requested.
  618.     if (fClearDirty)
  619.         pThis->m_bModified = FALSE;
  620.  
  621.     return hr;
  622. }
  623.